package Fifteen;

import java.util.LinkedList;
import java.util.Queue;

import javax.swing.JFrame;

////////////////////////////////////////////////////////////////////////////////
//CLASS PUZZLELOGIC
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//Begin class definition PuzzleLogic
//Class PuzzleLogic maintains the logic of the slide puzzle.
////////////////////////////////////////////////////////////////////////////////
class PuzzleLogic{
	public int[] emptyPos;                          //  array that keeps track
	//  of the empty position
	public MovableButton[][] puzzleArray;           //  array that keeps track
	//  of the positions of the 
	//  buttons in the array
	public MovableButton[] buttonTrack;             //  array the maintains
	//  specific references to 
	//  buttons
	public int[][] solvedArray = {{1, 5, 9, 13},    //  array that maintains
			{2, 6, 10, 14},   //  the solved position
			{3, 7, 11, 15},
			{4, 8, 12, 0}};

	////////////////////////////////////////////////////////////////////////////
	//  Begin definition of the constructor PuzzleLogic
	//      The method PuzzleLogic() initializes the puzzles logic.
	////////////////////////////////////////////////////////////////////////////
	public PuzzleLogic(){
		emptyPos = new int[2];                      //  allocate new space for
		//  emptyPos
		emptyPos[0] = 3;                            //  set the x-axis position
		//  of the empty space to 3
		emptyPos[1] = 3;                            //  set the y-axis position
		//  of the empty space to 3
		puzzleArray = new MovableButton[4][4];      //  allocate new space for
		//  puzzleArray
		buttonTrack = new MovableButton[16];        //  allocate new space for
		//  buttonTrack
	}   //  end definition of constructor method public PuzzleLogic()

	////////////////////////////////////////////////////////////////////////////
	//  Begin definition of method PositionOfClear
	//      Method PositionOfClear() returns the array indicating the position
	//  of emptyPos.
	////////////////////////////////////////////////////////////////////////////
	public int[] PositionOfClear(){
		//  return the position of emptyPos
		return emptyPos;
	}   //  end definition of method public int[] PositionOfClear()

	////////////////////////////////////////////////////////////////////////////
	//  Begin definition of method Move
	//      Method Move updates the arrays original position and final position
	//  of the puzzleArray
	////////////////////////////////////////////////////////////////////////////
	public void Move(int[] originalPos, int[] finalPos){
		emptyPos[0] = originalPos[0];               //  update empty x position
		emptyPos[1] = originalPos[1];               //  update empty y position
		//  set placeholder MovableButton to reference the button at final
		//  position
		MovableButton placeHolder = puzzleArray[finalPos[0]][finalPos[1]];
		//  set MovableButton at final position to be MovableButton at original
		//  position
		puzzleArray[finalPos[0]][finalPos[1]] = puzzleArray[originalPos[0]]
				[originalPos[1]];
		//  set MovableButton at original position to reference the button 
		//  placeholder references
		puzzleArray[originalPos[0]][originalPos[1]] = placeHolder;
	}   //  end definition of method public void Move

	////////////////////////////////////////////////////////////////////////////
	//  Begin definition of method Solved
	//      Method Solved() checks if the puzzle is solved and if it is
	//  presents a message dialogue informing the user.
	////////////////////////////////////////////////////////////////////////////
	public void Solved(){
		Boolean solved = true;                  //  set solved equal to true
		//  for each row
		for(int i = 0; i < 4; i++){
			//  for each column
			for(int j = 0; j < 4; j++){
				//  if the integer displayed in text on the button at the given 
				//  position does not match the integer in the same position of
				//  the solved array then 
				if(Integer.parseInt(puzzleArray[i][j].getText())  
						!= solvedArray[i][j])
					solved = false; //  set solved equal to false
			}   //  end for(int j = 0; j < 4; j++)
		}   //  end for(int i = 0; i < 4; i++)
		//  if the puzzle is solved
		if(solved){
			//  make a new frame for informing the user the 
			//  puzzle is solved.
			JFrame solvedFrame = new JFrame("Solved!");
			//  set the size of the frame
			solvedFrame.setSize(200,100);
			//  set the location of the frame
			solvedFrame.setLocationRelativeTo(null);
			//  set the frame to dispose on close
			solvedFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
			//  set the frame to ve visible
			solvedFrame.setVisible(true);
		}   //  end if(solved)
	}   //  end definition of method public void Solved()

	////////////////////////////////////////////////////////////////////////////
	//  Begin definition of method Scramble
	//      Method Scramble scrambles the buttons of the puzzle by iterating
	//  through legal moves.
	////////////////////////////////////////////////////////////////////////////
	public void Scramble(){
		System.out.println("Entered PuzzleLogicMethod Scramble");
		Queue<String> posMoves = new LinkedList<String>();      //  Queue for storing
		//  possible ways the empty
		//  position can move
		int rand1;                              //  integer storage for
		//  a random integer
		int rand2;                              //  integer storage for
		//  a random integer

		//  assign rand1 a random integer between 5 and 55
		rand1 = ((int)(Math.random() * 10) + 1) * 5;
		//  from zero to rand1
		for(int i = 0; i < rand1; i++){
			//  if the empty spot can move right
			if(emptyPos[0] < 3){
				//  add "Right" to the possible moves queue
				posMoves.add("Right");
			}   //  end if(emptyPos[0] < 3)
			//  if the empty spot can move left
			if(emptyPos[0] > 0){
				//  add "Left" to the possible moves queue
				posMoves.add("Left");
			}   //  end if(emptyPos[0] > 0)
			//  if the empty spot can move down
			if(emptyPos[1] < 3){
				//  add "Down" to the possible moves queue
				posMoves.add("Down");
			}   //  end if(emptyPos[1] < 3)
			//  if the empty spot can move up
			if(emptyPos[1] > 0){
				//  add "Up" to the possible moves queue
				posMoves.add("Up");
			}   //  end if(emptyPos[1] > 0)

			//  assign rand2 and random integer between
			//  one and 55
			rand2 = (((int)(Math.random() * 10)+ 1) + 5);
			//  from zero to rand2
			for(int j = 0; j < rand2; j++){
				//  spin the queue by popping x of the front of
				//  the queue and pushing x on the back
				posMoves.add(posMoves.remove());
			}   //  end for(int j = 0; j < rand2; j++)
			//  set the move to the string on the front of the queue
			String move = (String)(posMoves.remove());
			//  if move empty space down
			if(move.equals("Down")){
				//  move the button below the empty space
				puzzleArray[emptyPos[0]][emptyPos[1] + 1].MoveButton();
			}   //  end if(move.equals("Down"))
			//  else the empty space is not to move down so if the
			//  empty space is to move up
			else if(move.equals("Up")){
				//  move the button above the empty space
				puzzleArray[emptyPos[0]][emptyPos[1] - 1].MoveButton();
			}   //  end else if(move.equals("Up"))
			//  else the empty space is not to move up so if the 
			//  empty space is to move right
			else if(move.equals("Right")){
				//  move the button to the right of the empty space
				puzzleArray[emptyPos[0] + 1][emptyPos[1]].MoveButton();
			}   //  end else if(move.equals("Right"))
			//  else the empty space is not to move right so if the
			//  empty space is to move left
			else if(move.equals("Left")){
				//  move the button to the left of the empty space
				puzzleArray[emptyPos[0] - 1][emptyPos[1]].MoveButton();
			}   //  end else if(move.equals("Left"))
			//  clear the possible moves queue for the next run through
			posMoves.clear();
		}   //   end for(int i = 0; i < rand1; i++)
	}   //  end definition of method public void Scramble()

	////////////////////////////////////////////////////////////////////////////
	//  Begin definition of method Reset()
	//      Method Reset sets the logic of the puzzle to the intial state
	////////////////////////////////////////////////////////////////////////////
	public void Reset(){

		emptyPos[0] = 3;               //  set empty x position to 3
		emptyPos[1] = 3;               //  set empty y position to 3
		// for each slider
		for(int i = 0; i < 15; i++){
			//  set the reference of the current position to the slider
			//  it referenced originally
			puzzleArray[(i - 4 * (i/4))][i/4] = buttonTrack[i];
		}   //  end for(int i = 0; i < 15; i++)
		puzzleArray[3][3] = buttonTrack[15];
	}   //  end definition of method public void Reset()
}   //  end definiton of class PuzzleLogic
////////////////////////////////////////////////////////////////////////////////
//END PUZZLELOGIC CLASS
////////////////////////////////////////////////////////////////////////////////